package cn.bugDance.trigger.http;

import cn.bugDance.api.activity.controller.IRaffleActivityController;
import cn.bugDance.api.activity.dto.*;
import cn.bugDance.domain.activity.model.entity.*;
import cn.bugDance.domain.activity.model.valobj.TradeTypeVO;
import cn.bugDance.domain.activity.service.IRaffleActivityPartakeService;
import cn.bugDance.domain.activity.service.quota.IRaffleActivityQuotaService;
import cn.bugDance.domain.activity.service.IRaffleActivityService;
import cn.bugDance.domain.activity.service.armory.IRaffleActivityArmory;
import cn.bugDance.domain.award.service.IAwardService;
import cn.bugDance.domain.credit.model.entity.TradeEntity;
import cn.bugDance.domain.credit.model.valobj.TradeNameVO;
import cn.bugDance.domain.credit.service.ICreditAccountAdjustService;
import cn.bugDance.domain.rebate.model.entity.BehaviorEntity;
import cn.bugDance.domain.rebate.model.valobj.BehaviorVO;
import cn.bugDance.domain.rebate.service.IRebateQuotaService;
import cn.bugDance.domain.rebate.service.IRebateService;
import cn.bugDance.domain.strategy.model.entity.RaffleAwardEntity;
import cn.bugDance.domain.strategy.model.entity.RaffleFactorEntity;
import cn.bugDance.domain.strategy.model.entity.StrategyAwardEntity;
import cn.bugDance.domain.strategy.model.valobj.RuleWeightVO;
import cn.bugDance.domain.strategy.model.valobj.StrategyConstant;
import cn.bugDance.domain.strategy.service.IRaffleStrategyService;
import cn.bugDance.domain.strategy.service.IStrategyQuotaService;
import cn.bugDance.domain.strategy.service.armory.IRaffleStrategyArmory;
import cn.bugDance.types.annotations.DynamicConfigValue;
import cn.bugDance.types.annotations.RateLimiterAccessInterceptor;
import cn.bugDance.types.enums.ResponseCode;
import cn.bugDance.types.exception.AppException;
import cn.bugDance.types.response.Response;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@RestController()
@RequestMapping("/raffle/${app.config.api-version}/activity")
@CrossOrigin("${app.config.cross-origin}")
@Slf4j
public class ActivityController implements IRaffleActivityController {

    @Resource
    private IRaffleActivityService raffleActivityService;
    @Resource
    private IRaffleActivityArmory raffleActivityArmory;
    @Resource
    private IRaffleActivityPartakeService raffleActivityPartakeService;
    @Resource
    private IAwardService awardService;
    @Resource
    private IRaffleStrategyService raffleStrategyService;
    @Resource
    private IRaffleStrategyArmory raffleStrategyArmory;
    @Resource
    private IRaffleActivityQuotaService raffleActivityQuotaService;
    @Resource
    private IRebateService rebateService;
    @Resource
    private IStrategyQuotaService strategyQuotaService;
    @Resource
    private IRebateQuotaService rebateQuotaService;
    @Resource
    private ICreditAccountAdjustService creditAccountAdjustService;


    private final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
    private final SimpleDateFormat monthFormat = new SimpleDateFormat("yyyy-MM");



    @Override
    @HystrixCommand(
            commandProperties = {
                    @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "150")
            },
            fallbackMethod = "HystrixError"
    )
    @RequestMapping(method = RequestMethod.POST, value = "/random_raffle")
    public Response<RaffleActivityResponseDTO> randomRaffle(@RequestBody RaffleActivityRequestDTO raffleActivityRequestDTO) {
        try{
            String userId = raffleActivityRequestDTO.getUserId();
            Long activityId = raffleActivityRequestDTO.getActivityId();
            log.info("【活动控制层-ActivityController】: 活动随机抽奖, userId: {}, activityId: {}", userId, activityId);


            PartakeActivityFactorEntity partakeActivityFactorEntity = new PartakeActivityFactorEntity();
            partakeActivityFactorEntity.setActivityId(activityId);
            partakeActivityFactorEntity.setUserId(userId);

            ActivityPartakeOrderEntity activityPartakeOrderEntity = raffleActivityPartakeService.partakeActivity(partakeActivityFactorEntity);

            RaffleFactorEntity raffleFactorEntity = new RaffleFactorEntity();
            raffleFactorEntity.setUserId(userId);
            raffleFactorEntity.setStrategyId(activityPartakeOrderEntity.getStrategyId());
            raffleFactorEntity.setEndDateTime(activityPartakeOrderEntity.getEndDateTime());
            raffleFactorEntity.setDay(dateFormat.format(new Date()));
            raffleFactorEntity.setActivityId(activityId);

            RaffleAwardEntity raffleAwardEntity = raffleStrategyService.performRaffle(raffleFactorEntity);

            awardService.saveAwardRecord(raffleAwardEntity, activityPartakeOrderEntity);

            RaffleActivityResponseDTO raffleActivityResponseDTO = new RaffleActivityResponseDTO();
            raffleActivityResponseDTO.setAwardId(raffleAwardEntity.getAwardId());
            raffleActivityResponseDTO.setAwardTitle(raffleAwardEntity.getAwardTitle());
            raffleActivityResponseDTO.setSort(raffleAwardEntity.getSort());

            return Response.<RaffleActivityResponseDTO>builder().
                    data(raffleActivityResponseDTO)
                    .code(ResponseCode.SUCCESS.getCode())
                    .info(ResponseCode.SUCCESS.getInfo()).build();
        }
        catch (AppException e){
            log.info("【活动控制层-ActivityController】: 活动随机抽奖失败1, message: {}", e.getInfo());
            return Response.<RaffleActivityResponseDTO>builder()
                    .code(e.getCode())
                    .info(e.getInfo()).build();
        }
        catch (Exception e){
            log.info("【活动控制层-ActivityController】: 活动随机抽奖失败2, message: {}", e.getMessage());
            return Response.<RaffleActivityResponseDTO>builder()
                    .code(ResponseCode.UN_ERROR.getCode())
                    .info(ResponseCode.UN_ERROR.getInfo()).build();
        }
    }

    @Override
    @RequestMapping(method = RequestMethod.GET, value = "/assemble")
    public Response<String> activityAssemble(@RequestParam Long activityId) {
        try{
            log.info("【活动控制层-ActivityController】: 活动预热装配, activityId: {}", activityId);
            Long strategyId = raffleActivityArmory.assembleRaffleActivity(activityId);
            Date endTime = raffleActivityArmory.queryActivityEndTime(activityId);
            raffleStrategyArmory.assembleRaffleStrategy(strategyId, endTime);
            return Response.<String>builder()
                    .code(ResponseCode.SUCCESS.getCode())
                    .info(ResponseCode.SUCCESS.getInfo()).build();
        }catch (Exception e){
            log.info("【活动控制层-ActivityController】: 活动预热失败, message: {}", e.getMessage());
            return Response.<String>builder()
                    .code(ResponseCode.UN_ERROR.getCode())
                    .info(ResponseCode.UN_ERROR.getInfo()).build();
        }
    }

    @Override
    @RequestMapping(method = RequestMethod.GET, value = "/query_award_list")
    public Response<List<RaffleActivityAwardListDTO>> queryActivityAwardList(@RequestParam Long activityId, @RequestParam String userId) {
        try{
            log.info("【活动控制层-ActivityController】: 查询抽奖奖品列表, activityId: {}", activityId);
            List<StrategyAwardEntity> strategyAwardEntities = raffleActivityArmory.queryStrategyAwardList(activityId);
            List<RaffleActivityAwardListDTO> activityAwardListDTOS = new ArrayList<>();

            if(strategyAwardEntities != null){
                for(StrategyAwardEntity strategyAwardEntity : strategyAwardEntities){
                    if(strategyAwardEntity.getRaffle() == 0){
                        RaffleActivityAwardListDTO raffleActivityAwardListDTO = new RaffleActivityAwardListDTO();
                        raffleActivityAwardListDTO.setAwardId(strategyAwardEntity.getAwardId());
                        raffleActivityAwardListDTO.setAwardTitle(strategyAwardEntity.getAwardTitle());
                        raffleActivityAwardListDTO.setAwardSubTitle(strategyAwardEntity.getAwardSubTitle());
                        raffleActivityAwardListDTO.setSort(strategyAwardEntity.getSort());

                        if(!StringUtils.isBlank(strategyAwardEntity.getRuleModels())){
                            List<String> ruleModels = strategyAwardEntity.ruleModels();
                            if(ruleModels.contains(StrategyConstant.StrategyRule.RULE_LOCK)){
                                Integer awardLockCount = raffleStrategyArmory.queryAwardRuleLockValue(strategyAwardEntity.getStrategyId(), strategyAwardEntity.getAwardId());
                                raffleActivityAwardListDTO.setAwardLockCount(awardLockCount);

                                Integer userDayCount = raffleActivityQuotaService.queryUserDayCount(userId, activityId);
                                raffleActivityAwardListDTO.setIsAwardLock(userDayCount >= awardLockCount);
                                raffleActivityAwardListDTO.setWaitUnlockCount(userDayCount < awardLockCount ? awardLockCount - userDayCount : 0);
                            }
                            else{
                                raffleActivityAwardListDTO.setIsAwardLock(Boolean.FALSE);
                            }
                        }
                        activityAwardListDTOS.add(raffleActivityAwardListDTO);
                    }
                }
            }

            return Response.<List<RaffleActivityAwardListDTO>>builder()
                    .code(ResponseCode.SUCCESS.getCode())
                    .info(ResponseCode.SUCCESS.getInfo())
                    .data(activityAwardListDTOS).build();

        }catch (Exception e){
            log.warn("【活动控制层-ActivityController】: 查询活动信息失败, activityId:{}", activityId);
            return Response.<List<RaffleActivityAwardListDTO>>builder()
                    .code(ResponseCode.UN_ERROR.getCode())
                    .info(ResponseCode.UN_ERROR.getInfo()).build();
        }
    }

    @Override
    @RequestMapping(value = "/calender_sign", method = RequestMethod.GET)
    public Response<Boolean> calendarSignRebate(@RequestParam String userId, @RequestParam Long activityId) {
        try{
            Date nowDate = new Date();
            BehaviorEntity behaviorEntity = new BehaviorEntity();
            behaviorEntity.setUserId(userId);
            behaviorEntity.setActivityId(activityId);
            behaviorEntity.setBehaviorType(BehaviorVO.CHECK_IN.getCode());
            behaviorEntity.setSignDay(dateFormat.format(nowDate));
            behaviorEntity.setSignMonth(monthFormat.format(nowDate));
            behaviorEntity.setNowDate(nowDate);

            rebateService.createUserBehaviorRebateOrder(behaviorEntity);
            return Response.<Boolean>builder()
                    .code(ResponseCode.SUCCESS.getCode())
                    .info(ResponseCode.SUCCESS.getInfo())
                    .data(true).build();
        }catch (AppException e){
            log.error("【活动控制层-ActivityController】: 返利服务异常, message: {}, userId: {}", e.getMessage(), userId);
            return Response.<Boolean>builder()
                    .code(e.getCode())
                    .info(e.getInfo())
                    .data(false).build();
        }catch (Exception e){
            log.error("【活动控制层-ActivityController】: 返利服务失败, message: {}, userId: {}", e.getMessage(), userId);
            return Response.<Boolean>builder()
                    .code(ResponseCode.UN_ERROR.getCode())
                    .info(ResponseCode.UN_ERROR.getInfo())
                    .data(false).build();
        }
    }

    @Override
    @RequestMapping(value = "/query_user_activity_account", method = RequestMethod.POST)
    public Response<RaffleActivityAccountResponseDTO> queryActivityAccount(@RequestBody RaffleActivityRequestDTO raffleActivityRequestDTO) {
        try{
            String userId = raffleActivityRequestDTO.getUserId();
            Long activityId = raffleActivityRequestDTO.getActivityId();

            Date nowDate = new Date();
            String month = monthFormat.format(nowDate);
            String day = dateFormat.format(nowDate);
            Integer totalCountSurplus = raffleActivityQuotaService.queryUserTotalCountSurplus(userId, activityId);
            Integer monthCountSurplus = raffleActivityQuotaService.queryUserMonthCountSurplus(userId, activityId, month);
            Integer dayCountSurplus = raffleActivityQuotaService.queryUserDayCountSurplus(userId, activityId, day);

            RaffleActivityAccountResponseDTO raffleActivityAccountResponseDTO = new RaffleActivityAccountResponseDTO();
            raffleActivityAccountResponseDTO.setDayCountSurplus(dayCountSurplus);
            raffleActivityAccountResponseDTO.setMonthCountSurplus(monthCountSurplus);
            raffleActivityAccountResponseDTO.setTotalCountSurplus(totalCountSurplus);

            return Response.<RaffleActivityAccountResponseDTO>builder()
                    .code(ResponseCode.SUCCESS.getCode())
                    .info(ResponseCode.SUCCESS.getInfo())
                    .data(raffleActivityAccountResponseDTO).build();
        }catch (Exception e){
            log.error("【活动控制层-ActivityController】: 查询用户活动账户失败");
            return Response.<RaffleActivityAccountResponseDTO>builder()
                    .code(ResponseCode.UN_ERROR.getCode())
                    .info(ResponseCode.UN_ERROR.getInfo())
                    .data(null).build();
        }
    }

    @Override
    @RequestMapping(value = "/query_raffle_strategy_rule_weight", method = RequestMethod.POST)
    public Response<List<RaffleStrategyRuleWeightResponseDTO>> queryRaffleStrategyRuleWeight(@RequestBody RaffleActivityRequestDTO raffleActivityRequestDTO) {
        try{
            String userId = raffleActivityRequestDTO.getUserId();
            Long activityId = raffleActivityRequestDTO.getActivityId();


            Integer userPartakeTotalCount = raffleActivityQuotaService.queryRaffleActivityAccountPartakeCount(userId, activityId);

            List<RuleWeightVO> ruleWeightVOS = strategyQuotaService.queryStrategyRuleWeight(activityId);
            List<RaffleStrategyRuleWeightResponseDTO> raffleStrategyRuleWeightResponseDTOS = new ArrayList<>();

            for(RuleWeightVO ruleWeightVO : ruleWeightVOS){
                Integer weight = ruleWeightVO.getWeight();
                List<RuleWeightVO.Award> awardList = ruleWeightVO.getAwardList();

                RaffleStrategyRuleWeightResponseDTO raffleStrategyRuleWeightResponseDTO = new RaffleStrategyRuleWeightResponseDTO();
                raffleStrategyRuleWeightResponseDTO.setRuleWeight(weight);
                raffleStrategyRuleWeightResponseDTO.setUserPartakeTotalCount(userPartakeTotalCount);
                List<RaffleStrategyRuleWeightResponseDTO.StrategyAward> strategyAwards = new ArrayList<>();
                for(RuleWeightVO.Award award : awardList){
                    RaffleStrategyRuleWeightResponseDTO.StrategyAward strategyAward = new RaffleStrategyRuleWeightResponseDTO.StrategyAward();

                    strategyAward.setAwardId(award.getAwardId());
                    strategyAward.setAwardTitle(award.getAwardTitle());

                    strategyAwards.add(strategyAward);
                }
                raffleStrategyRuleWeightResponseDTO.setStrategyAwards(strategyAwards);
                raffleStrategyRuleWeightResponseDTOS.add(raffleStrategyRuleWeightResponseDTO);
            }
            return Response.<List<RaffleStrategyRuleWeightResponseDTO>>builder()
                    .code(ResponseCode.SUCCESS.getCode())
                    .info(ResponseCode.SUCCESS.getInfo())
                    .data(raffleStrategyRuleWeightResponseDTOS).build();

        }catch (Exception e){
            log.error("【活动控制层-ActivityController】: 查询用户总抽奖次数和活动策略权重失败");
            return Response.<List<RaffleStrategyRuleWeightResponseDTO>>builder()
                    .code(ResponseCode.UN_ERROR.getCode())
                    .info(ResponseCode.UN_ERROR.getInfo())
                    .data(null).build();
        }
    }

    @Override
    @RequestMapping(value = "/is_calendar_sign_rebate", method = RequestMethod.GET)
    public Response<Boolean> isCalendarSignRebate(@RequestParam String userId, @RequestParam Long activityId) {
        try {
            Date nowDate = new Date();
            String outBusinessNo = dateFormat.format(nowDate);
            Boolean isisCalendarSign = rebateQuotaService.isCalendarSignRebate(userId, activityId, outBusinessNo);

            return Response.<Boolean>builder()
                    .code(ResponseCode.SUCCESS.getCode())
                    .info(ResponseCode.SUCCESS.getInfo())
                    .data(isisCalendarSign).build();
        } catch (Exception e) {
            return Response.<Boolean>builder()
                    .code(ResponseCode.UN_ERROR.getCode())
                    .info(ResponseCode.UN_ERROR.getInfo())
                    .data(false).build();
        }
    }

    @Override
    @RequestMapping(value = "/query_user_available_amount", method = RequestMethod.GET)
    public Response<Integer> queryUserAvailableCreditAmount(@RequestParam String userId) {
        try{
            log.info("【ActivityController->】: 用户: {}, 查询可用积分", userId);
            Integer availableAmount = creditAccountAdjustService.queryAvailableAmount(userId);
            return Response.<Integer>builder()
                    .code(ResponseCode.SUCCESS.getCode())
                    .info(ResponseCode.SUCCESS.getInfo())
                    .data(availableAmount).build();
        }catch (Exception e){
            log.error("【ActivityController->】: 用户: {}, 查询可用积分失败", userId);
            return Response.<Integer>builder()
                    .code(ResponseCode.UN_ERROR.getCode())
                    .info(ResponseCode.UN_ERROR.getInfo())
                    .data(0).build();
        }
    }

    @Override
    @RequestMapping(value = "/query_recharge_activity_skus", method = RequestMethod.GET)
    public Response<List<RechargeActivitySkuResponseDTO>> queryRechargeActivitySkus(@RequestParam Long activityId) {
        try{
            log.info("【ActivityController->】: 活动: {}, 查询活动下可兑换的sku列表", activityId);
            List<ActivitySkuEntity> activitySkuEntities = raffleActivityQuotaService.queryRechargeSku(activityId);
            List<RechargeActivitySkuResponseDTO> rechargeActivitySkuResponseDTOS = new ArrayList<>();
            for(ActivitySkuEntity activitySkuEntity : activitySkuEntities){
                RechargeActivitySkuResponseDTO rechargeActivitySkuResponseDTO = new RechargeActivitySkuResponseDTO();
                rechargeActivitySkuResponseDTO.setSku(activitySkuEntity.getSku());
                rechargeActivitySkuResponseDTO.setPayAmount(activitySkuEntity.getPayAmount());
                rechargeActivitySkuResponseDTO.setStockCountSurplus(activitySkuEntity.getStockCountSurplus());

                rechargeActivitySkuResponseDTOS.add(rechargeActivitySkuResponseDTO);
            }
            return Response.<List<RechargeActivitySkuResponseDTO>>builder()
                    .code(ResponseCode.SUCCESS.getCode())
                    .info(ResponseCode.SUCCESS.getInfo())
                    .data(rechargeActivitySkuResponseDTOS).build();
        }catch (Exception e){
            log.error("【ActivityController->】: 活动: {}, 查询活动下可兑换的sku列表出现异常", activityId);
            return Response.<List<RechargeActivitySkuResponseDTO>>builder()
                    .code(ResponseCode.UN_ERROR.getCode())
                    .info(ResponseCode.UN_ERROR.getInfo())
                    .data(null).build();
        }
    }

    @Override
    @RequestMapping(value = "/credit_recharge", method = RequestMethod.POST)
    public Response<Boolean> creditRecharge(@RequestBody CreditRechargeRequestDTO creditRechargeRequestDTO) {
        try{
            String userId = creditRechargeRequestDTO.getUserId();
            Long sku = creditRechargeRequestDTO.getSku();
            log.info("【ActivityController->】: 用户: {}, sku: {}, 积分兑换sku", userId, sku);

            // sku下单
            ActivityShopCartEntity activityShopCartEntity = new ActivityShopCartEntity();
            activityShopCartEntity.setSku(sku);
            activityShopCartEntity.setUserId(userId);
            activityShopCartEntity.setBizId(RandomStringUtils.randomNumeric(12));
            activityShopCartEntity.setTradeType(TradeTypeVO.credit_pay);

            ActivitySkuOrderEntity activitySkuOrderEntity = raffleActivityService.createActivitySkuOrder(activityShopCartEntity);

            ActivitySkuEntity activitySkuEntity = raffleActivityQuotaService.queryActivitySku(sku);

            // 积分支付
            TradeEntity tradeEntity = new TradeEntity();
            tradeEntity.setUserId(userId);
            tradeEntity.setTradeType(cn.bugDance.domain.credit.model.valobj.TradeTypeVO.REVERSE);
            tradeEntity.setTradeName(TradeNameVO.CONVERT_SKU);
            tradeEntity.setTradeAmount(activitySkuEntity.getPayAmount());
            tradeEntity.setBizId(activitySkuOrderEntity.getOrderId());

            creditAccountAdjustService.createOrder(tradeEntity);
            return Response.<Boolean>builder()
                    .code(ResponseCode.SUCCESS.getCode())
                    .info(ResponseCode.SUCCESS.getInfo())
                    .data(true).build();

        }catch (AppException e){
            log.warn("【ActivityController->】: 积分订单插入异常");
            return Response.<Boolean>builder()
                    .code(e.getCode())
                    .info(e.getInfo())
                    .data(false).build();
        }catch (Exception e){
            log.warn("【ActivityController->】: 积分订单插入出错");
            return Response.<Boolean>builder()
                    .code(ResponseCode.UN_ERROR.getCode())
                    .info(ResponseCode.UN_ERROR.getInfo())
                    .data(false).build();
        }
    }


    public Response<RaffleActivityResponseDTO> rateLimitError(@RequestBody RaffleActivityRequestDTO raffleActivityRequestDTO){
        return Response.<RaffleActivityResponseDTO>builder()
                .code(ResponseCode.RATE_LIMIT.getCode())
                .info(ResponseCode.RATE_LIMIT.getInfo())
                .data(null).build();
    }

    public Response<RaffleActivityResponseDTO> HystrixError(@RequestBody RaffleActivityRequestDTO raffleActivityRequestDTO){
        return Response.<RaffleActivityResponseDTO>builder()
                .code(ResponseCode.HYSTRIX.getCode())
                .info(ResponseCode.HYSTRIX.getInfo())
                .data(null).build();
    }

}
